bitkeeper revision 1.1159.231.12 (41f97ef6r1c2TDcgR-o8jFV1IWm5dA)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Thu, 27 Jan 2005 23:53:26 +0000 (23:53 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Thu, 27 Jan 2005 23:53:26 +0000 (23:53 +0000)
Lean decoder for MMIO instructions.

Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Chengyuan Li <chengyuan.li@intel.com>
Signed-off-by: ian.pratt@cl.cam.ac.uk
.rootkeys
xen/arch/x86/vmx.c
xen/arch/x86/vmx_io.c
xen/arch/x86/vmx_platform.c [new file with mode: 0644]
xen/include/asm-x86/shadow.h
xen/include/asm-x86/vmx_platform.h
xen/include/asm-x86/vmx_vmcs.h

index 9f2d05bfccf21b5bca25f7ccda179c0ad8233907..a1e6da4afc0fe1278a258d42e48f7bd32810280c 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
 41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
 41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
+41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c
 41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c
 419cbedeQDg8IrO3izo3o5rQNlo0kQ xen/arch/x86/x86_32/asm-offsets.c
 3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c
index acfc14eb4ce9db6a91b4c213a975c3e62789f781..010bccbba33dec985801e76338406293a1c1c933 100644 (file)
@@ -107,7 +107,7 @@ static int vmx_do_page_fault(unsigned long va, unsigned long error_code)
 {
     unsigned long eip, pfn;
     unsigned int index;
-    unsigned long gpde = 0;
+    unsigned long gpde = 0, gpte, gpa;
     int result;
     struct exec_domain *ed = current;
     struct mm_struct *m = &ed->mm;
@@ -137,6 +137,15 @@ static int vmx_do_page_fault(unsigned long va, unsigned long error_code)
         m->guest_pl2e_cache[index] = 
             mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
     }
+    
+    if (unlikely(__get_user(gpte, (unsigned long *)
+                            &linear_pg_table[va >> PAGE_SHIFT])))
+        return 0;
+    
+    gpa = (gpte & PAGE_MASK) | (va & (PAGE_SIZE - 1));
+
+    if (mmio_space(gpa))
+        handle_mmio(va, gpte, gpa);
 
     if ((result = shadow_fault(va, error_code)))
         return result;
@@ -283,7 +292,7 @@ static inline void guest_pl2e_cache_invalidate(struct mm_struct *m)
     memset(m->guest_pl2e_cache, 0, PAGE_SIZE);
 }
 
-static inline unsigned long gva_to_gpa(unsigned long gva)
+inline unsigned long gva_to_gpa(unsigned long gva)
 {
     unsigned long gpde, gpte, pfn, index;
     struct exec_domain *d = current;
@@ -784,6 +793,7 @@ asmlinkage void vmx_vmexit_handler(struct xen_regs regs)
             __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
             VMX_DBG_LOG(DBG_LEVEL_VMMU, 
                     "eax=%x, ebx=%x, ecx=%x, edx=%x, esi=%x, edi=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx, regs.esi, regs.edi);
+            d->thread.arch_vmx.vmx_platform.mpci.inst_decoder_regs = &regs;
 
             if (!(error = vmx_do_page_fault(va, error_code))) {
                 /*
index 85862f94ea94f426512dc4d447e6232f83e4c4a9..652bf3613de2aa07390a57c077a5db0a32e8e9f1 100644 (file)
 #include <asm/vmx_vmcs.h>
 #include <xen/event.h>
 #include <public/io/ioreq.h>
+#include <asm/vmx_platform.h>
 
 extern long do_block();
+  
+#if defined (__i386__)
+static void load_xen_regs(struct xen_regs *regs)
+{ 
+    /*
+     * Write the guest register value into VMCS
+     */
+    __vmwrite(GUEST_SS_SELECTOR, regs->ss);
+    __vmwrite(GUEST_ESP, regs->esp);
+    __vmwrite(GUEST_EFLAGS, regs->eflags);
+    __vmwrite(GUEST_CS_SELECTOR, regs->cs);
+    __vmwrite(GUEST_EIP, regs->eip);
+}
+
+static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value)
+{
+    switch (size) {
+    case BYTE:
+        switch (index) {
+        case 0:
+            regs->eax &= 0xFFFFFF00;
+            regs->eax |= (value & 0xFF);
+            break;
+        case 1:
+            regs->ecx &= 0xFFFFFF00;
+            regs->ecx |= (value & 0xFF);
+            break;
+        case 2:
+            regs->edx &= 0xFFFFFF00;
+            regs->edx |= (value & 0xFF);
+            break;
+        case 3:
+            regs->ebx &= 0xFFFFFF00;
+            regs->ebx |= (value & 0xFF);
+            break;
+        case 4:
+            regs->eax &= 0xFFFF00FF;
+            regs->eax |= ((value & 0xFF) << 8);
+            break;
+        case 5:
+            regs->ecx &= 0xFFFF00FF;
+            regs->ecx |= ((value & 0xFF) << 8);
+            break;
+        case 6:
+            regs->edx &= 0xFFFF00FF;
+            regs->edx |= ((value & 0xFF) << 8);
+            break;
+        case 7:
+            regs->ebx &= 0xFFFF00FF;
+            regs->ebx |= ((value & 0xFF) << 8);
+            break;
+        default:
+            printk("size:%x, index:%x are invalid!\n", size, index);
+            break;
+
+        }
+        break;
+    case WORD:
+        switch (index) {
+        case 0:
+            regs->eax &= 0xFFFF0000;
+            regs->eax |= (value & 0xFFFF);
+            break;
+        case 1:
+            regs->ecx &= 0xFFFF0000;
+            regs->ecx |= (value & 0xFFFF);
+            break;
+        case 2:
+            regs->edx &= 0xFFFF0000;
+            regs->edx |= (value & 0xFFFF);
+            break;
+        case 3:
+            regs->ebx &= 0xFFFF0000;
+            regs->ebx |= (value & 0xFFFF);
+            break;
+        case 4:
+            regs->esp &= 0xFFFF0000;
+            regs->esp |= (value & 0xFFFF);
+            break;
+
+        case 5:
+            regs->ebp &= 0xFFFF0000;
+            regs->ebp |= (value & 0xFFFF);
+            break;
+        case 6:
+            regs->esi &= 0xFFFF0000;
+            regs->esi |= (value & 0xFFFF);
+            break;
+        case 7:
+            regs->edi &= 0xFFFF0000;
+            regs->edi |= (value & 0xFFFF);
+            break;
+        default:
+            printk("size:%x, index:%x are invalid!\n", size, index);
+            break;
+        }
+        break;
+    case LONG:
+        switch (index) {
+        case 0:
+            regs->eax = value;
+            break;
+        case 1:
+            regs->ecx = value;
+            break;
+        case 2:
+            regs->edx = value;
+            break;
+        case 3:
+            regs->ebx = value;
+            break;
+        case 4:
+            regs->esp = value;
+            break;
+        case 5:
+            regs->ebp = value;
+            break;
+        case 6:
+            regs->esi = value;
+            break;
+        case 7:
+            regs->edi = value;
+            break;
+        default:
+            printk("size:%x, index:%x are invalid!\n", size, index);
+            break;
+        }
+        break;
+    default:
+        printk("size:%x, index:%x are invalid!\n", size, index);
+        break;
+    }
+}
+#endif
 
 void vmx_io_assist(struct exec_domain *ed) 
 {
@@ -40,6 +175,11 @@ void vmx_io_assist(struct exec_domain *ed)
     execution_context_t *ec = get_execution_context();
     unsigned long old_eax;
     int sign;
+    struct mi_per_cpu_info *mpci_p;
+    struct xen_regs *inst_decoder_regs;
+
+    mpci_p = &ed->thread.arch_vmx.vmx_platform.mpci;
+    inst_decoder_regs = mpci_p->inst_decoder_regs;
 
     /* clear the pending event */
     ed->vcpu_info->evtchn_upcall_pending = 0;
@@ -76,7 +216,19 @@ void vmx_io_assist(struct exec_domain *ed)
             if (p->dir == IOREQ_WRITE) {
                 return;
             }
+            int size = -1, index = -1;
+
+            size = operand_size(ed->thread.arch_vmx.vmx_platform.mpci.mmio_target);
+            index = operand_index(ed->thread.arch_vmx.vmx_platform.mpci.mmio_target);
+
+            if (ed->thread.arch_vmx.vmx_platform.mpci.mmio_target & WZEROEXTEND) {
+                p->u.data = p->u.data & 0xffff;
+            }        
+            set_reg_value(size, index, 0, (struct xen_regs *)ec, p->u.data);
+
         }
+        load_xen_regs((struct xen_regs *)ec);
+        return;
     }
 
     if (p->dir == IOREQ_WRITE) {
diff --git a/xen/arch/x86/vmx_platform.c b/xen/arch/x86/vmx_platform.c
new file mode 100644 (file)
index 0000000..9ee99cd
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * vmx_platform.c: handling x86 platform related MMIO instructions
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/mm.h>
+#include <asm/shadow.h>
+#include <asm/domain_page.h>
+#include <asm/page.h> 
+#include <xen/event.h> 
+#include <xen/trace.h>
+#include <asm/vmx.h>
+#include <asm/vmx_platform.h>
+#include <public/io/ioreq.h>
+
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+
+#define DECODE_success  1
+#define DECODE_failure  0
+
+#if defined (__x86_64__)
+static void store_xen_regs(struct xen_regs *regs)
+{
+
+}
+
+static long get_reg_value(int size, int index, int seg, struct xen_regs *regs) 
+{
+    return 0;
+}
+#elif defined (__i386__)
+static void store_xen_regs(struct xen_regs *regs)
+{
+    __vmread(GUEST_SS_SELECTOR, &regs->ss);
+    __vmread(GUEST_ESP, &regs->esp);
+    __vmread(GUEST_EFLAGS, &regs->eflags);
+    __vmread(GUEST_CS_SELECTOR, &regs->cs);
+    __vmread(GUEST_EIP, &regs->eip);
+}
+
+static long get_reg_value(int size, int index, int seg, struct xen_regs *regs)
+{                    
+    /*               
+     * Reference the db_reg[] table
+     */              
+    switch (size) {  
+    case BYTE: 
+        switch (index) { 
+        case 0: //%al
+            return (char)(regs->eax & 0xFF);
+        case 1: //%cl  
+            return (char)(regs->ecx & 0xFF);
+        case 2: //%dl
+            return (char)(regs->edx & 0xFF); 
+        case 3: //%bl
+            return (char)(regs->ebx & 0xFF);
+        case 4: //%ah
+            return (char)((regs->eax & 0xFF00) >> 8);
+        case 5: //%ch 
+            return (char)((regs->ecx & 0xFF00) >> 8);
+        case 6: //%dh
+            return (char)((regs->edx & 0xFF00) >> 8);
+        case 7: //%bh
+            return (char)((regs->ebx & 0xFF00) >> 8);
+        default:
+            printk("(get_reg_value)size case 0 error\n"); 
+            return -1; 
+        }
+    case WORD:
+        switch (index) {
+        case 0: //%ax
+            return (short)(regs->eax & 0xFFFF);
+        case 1: //%cx
+            return (short)(regs->ecx & 0xFFFF);
+        case 2: //%dx
+            return (short)(regs->edx & 0xFFFF);
+        case 3: //%bx
+            return (short)(regs->ebx & 0xFFFF);
+        case 4: //%sp
+            return (short)(regs->esp & 0xFFFF);
+            break;
+        case 5: //%bp
+            return (short)(regs->ebp & 0xFFFF);
+        case 6: //%si
+            return (short)(regs->esi & 0xFFFF);
+        case 7: //%di
+            return (short)(regs->edi & 0xFFFF);
+        default:
+            printk("(get_reg_value)size case 1 error\n");
+            return -1;
+        }
+    case LONG:
+        switch (index) {
+        case 0: //%eax
+            return regs->eax;
+        case 1: //%ecx
+            return regs->ecx;
+        case 2: //%edx
+            return regs->edx;
+
+        case 3: //%ebx
+            return regs->ebx;
+        case 4: //%esp
+            return regs->esp;
+        case 5: //%ebp
+            return regs->ebp;
+        case 6: //%esi
+            return regs->esi;
+        case 7: //%edi
+            return regs->edi;
+        default:
+            printk("(get_reg_value)size case 2 error\n");
+            return -1;
+        }
+    default:
+        printk("(get_reg_value)size case error\n");
+        return -1;
+    }
+}
+#endif
+
+static inline unsigned char *check_prefix(unsigned char *inst, struct instruction *thread_inst)
+{
+    while (1) {
+        switch (*inst) {
+            case 0xf3: //REPZ
+            case 0xf2: //REPNZ
+            case 0xf0: //LOCK
+            case 0x2e: //CS
+            case 0x36: //SS
+            case 0x3e: //DS
+            case 0x26: //ES
+            case 0x64: //FS
+            case 0x65: //GS
+                break;
+            case 0x66: //32bit->16bit
+                thread_inst->op_size = WORD;
+                break;
+            case 0x67:
+                break;
+            default:
+                return inst;
+        }
+        inst++;
+    }
+}
+
+static inline unsigned long get_immediate(const unsigned char *inst, int op_size)
+{
+    int mod, reg, rm;
+    unsigned long val = 0;
+    int i;
+
+    mod = (*inst >> 6) & 3;
+    reg = (*inst >> 3) & 7;
+    rm = *inst & 7;
+
+    inst++; //skip ModR/M byte
+    if (mod != 3 && rm == 4) {
+        inst++; //skip SIB byte
+    }
+
+    switch(mod) {
+        case 0:
+            if (rm == 5) {
+                inst = inst + 4; //disp32, skip 4 bytes
+            }
+            break;
+        case 1:
+            inst++; //disp8, skip 1 byte
+            break;
+        case 2:
+            inst = inst + 4; //disp32, skip 4 bytes
+    }
+    for (i = 0; i < op_size; i++) {
+        val |= (*inst++ & 0xff) << (8 * i);
+    }
+    
+    return val;
+}
+
+static inline int get_index(const unsigned char *inst)
+{
+    int mod, reg, rm;
+
+    mod = (*inst >> 6) & 3;
+    reg = (*inst >> 3) & 7;
+    rm = *inst & 7;
+
+    //Only one operand in the instruction is register
+    if (mod == 3) {
+        return rm;
+    } else {
+        return reg;
+    }
+    return 0;
+}
+
+static int vmx_decode(const unsigned char *inst, struct instruction *thread_inst)
+{
+    int index;
+
+    switch(*inst) {
+        case 0x88:
+            /* mov r8 to m8 */
+            thread_inst->op_size = BYTE;
+            index = get_index((inst + 1));
+            thread_inst->operand[0] = mk_operand(BYTE, index, 0, REGISTER);
+            break;
+        case 0x89:
+            /* mov r32/16 to m32/16 */
+            index = get_index((inst + 1));
+            if (thread_inst->op_size == WORD) {
+                thread_inst->operand[0] = mk_operand(WORD, index, 0, REGISTER);
+            } else {
+                thread_inst->op_size = LONG;
+                thread_inst->operand[0] = mk_operand(LONG, index, 0, REGISTER);
+            }
+            break;
+        case 0x8a:
+            /* mov m8 to r8 */
+            thread_inst->op_size = BYTE;
+            index = get_index((inst + 1));
+            thread_inst->operand[1] = mk_operand(BYTE, index, 0, REGISTER);
+            break;
+        case 0x8b:
+            /* mov r32/16 to m32/16 */
+            index = get_index((inst + 1));
+            if (thread_inst->op_size == WORD) {
+                thread_inst->operand[1] = mk_operand(WORD, index, 0, REGISTER);
+            } else {
+                thread_inst->op_size = LONG;
+                thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER);
+            }
+            break;
+        case 0x8c:
+        case 0x8e:
+            printk("%x, This opcode hasn't been handled yet!", *inst);
+            return DECODE_failure;
+            /* Not handle it yet. */
+
+        case 0xa0:
+            /* mov byte to al */
+            thread_inst->op_size = BYTE;
+            thread_inst->operand[1] = mk_operand(BYTE, 0, 0, REGISTER);
+            break;
+        case 0xa1:
+            /* mov word/doubleword to ax/eax */
+            if (thread_inst->op_size == WORD) {
+                thread_inst->operand[1] = mk_operand(WORD, 0, 0, REGISTER);
+            } else {
+                thread_inst->op_size = LONG;
+                thread_inst->operand[1] = mk_operand(LONG, 0, 0, REGISTER);
+            }
+            break;
+        case 0xa2:
+            /* mov al to (seg:offset) */
+            thread_inst->op_size = BYTE;
+            thread_inst->operand[0] = mk_operand(BYTE, 0, 0, REGISTER);
+            break;
+        case 0xa3:
+            /* mov ax/eax to (seg:offset) */
+            if (thread_inst->op_size == WORD) {
+                thread_inst->operand[0] = mk_operand(WORD, 0, 0, REGISTER);
+            } else {
+                thread_inst->op_size = LONG;
+                thread_inst->operand[0] = mk_operand(LONG, 0, 0, REGISTER);
+            }
+            break;
+        case 0xa4:
+            /* movsb */
+            thread_inst->op_size = BYTE;
+            strcpy(thread_inst->i_name, "movs");
+            
+            return DECODE_success;
+        case 0xa5:
+            /* movsw/movsl */
+            if (thread_inst->op_size == WORD) {
+            } else {
+                thread_inst->op_size = LONG;
+            }
+            
+            strcpy(thread_inst->i_name, "movs");
+            
+            return DECODE_success;
+
+        case 0xc6:
+            /* mov imm8 to m8 */
+            thread_inst->op_size = BYTE;
+            thread_inst->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE);
+            thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size);
+            break;
+        case 0xc7:
+            /* mov imm16/32 to m16/32 */
+            if (thread_inst->op_size == WORD) {
+                thread_inst->operand[0] = mk_operand(WORD, 0, 0, IMMEDIATE);
+            } else {
+                thread_inst->op_size = LONG;
+                thread_inst->operand[0] = mk_operand(LONG, 0, 0, IMMEDIATE);
+            }
+            thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size);
+            break;
+
+        case 0x0f:
+            break;
+        default:
+            printk("%x, This opcode hasn't been handled yet!", *inst);
+            return DECODE_failure;
+    }
+    
+    strcpy(thread_inst->i_name, "mov");
+    if (*inst != 0x0f) {
+        return DECODE_success;
+    }
+
+    inst++;
+    switch (*inst) {
+                    
+        /* movz */
+        case 0xb7:
+            index = get_index((inst + 1));
+            thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER);
+            strcpy(thread_inst->i_name, "movzw");
+            
+            return DECODE_success;
+        default:
+            printk("0f %x, This opcode hasn't been handled yet!", *inst);
+            return DECODE_failure;
+    }
+
+    /* will never reach here */
+    return DECODE_failure;
+}
+
+static int inst_copy_from_guest(char *buf, unsigned long guest_eip, int inst_len)
+{
+    unsigned long gpte;
+    unsigned long mfn;
+    unsigned long ma;
+    unsigned char * inst_start;
+        
+    if (inst_len > MAX_INST_LEN || inst_len <= 0) {
+        return 0;
+    }
+
+    if ((guest_eip & PAGE_MASK) == ((guest_eip + inst_len) & PAGE_MASK)) {
+        if ( unlikely(__get_user(gpte, (unsigned long *)
+                                 &linear_pg_table[guest_eip >> PAGE_SHIFT])) )
+            {
+                printk("inst_copy_from_guest- EXIT: read gpte faulted" );
+                return 0;
+            }
+        mfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+        ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1));
+        inst_start = (unsigned char *)map_domain_mem(ma);
+                
+        strncpy(buf, inst_start, inst_len);
+        unmap_domain_mem(inst_start);
+    } else {
+        // Todo: In two page frames
+    }
+        
+    return inst_len;
+}
+
+static void init_instruction(struct instruction *mmio_inst)
+{
+    memset(mmio_inst->i_name, '0', I_NAME_LEN);
+    mmio_inst->op_size =  0;
+    mmio_inst->offset = 0;
+    mmio_inst->immediate = 0;
+    mmio_inst->seg_sel = 0;
+    mmio_inst->op_num = 0;
+
+    mmio_inst->operand[0] = 0;
+    mmio_inst->operand[1] = 0;
+    mmio_inst->operand[2] = 0;
+        
+    mmio_inst->flags = 0;
+}
+
+static int read_from_mmio(struct instruction *inst_p)
+{
+    // Only for mov instruction now!!!
+    if (inst_p->operand[1] & REGISTER)
+        return 1;
+
+    return 0;
+}
+
+// dir:  1 read from mmio
+//       0 write to mmio
+static void send_mmio_req(unsigned long gpa, 
+                   struct instruction *inst_p, long value, int dir, int pvalid)
+{
+    struct exec_domain *d = current;
+    vcpu_iodata_t *vio;
+    ioreq_t *p;
+    struct mi_per_cpu_info *mpci_p;
+    struct xen_regs *inst_decoder_regs;
+    extern inline unsigned long gva_to_gpa(unsigned long gva);
+    extern long evtchn_send(int lport);
+    extern long do_block(void);
+
+    mpci_p = &current->thread.arch_vmx.vmx_platform.mpci;
+    inst_decoder_regs = mpci_p->inst_decoder_regs;
+    vio = (vcpu_iodata_t *) d->thread.arch_vmx.vmx_platform.shared_page_va;
+        
+    if (vio == NULL) {
+        printk("bad shared page\n");
+        domain_crash(); 
+    }
+    p = &vio->vp_ioreq;
+        
+    set_bit(ARCH_VMX_IO_WAIT, &d->thread.arch_vmx.flags);
+    p->dir = dir;
+    p->pdata_valid = pvalid;
+    p->count = 1;
+
+    p->port_mm = 1;
+    p->size = inst_p->op_size;
+    p->addr = gpa;
+    p->u.data = value;
+
+    // p->state = STATE_UPSTREAM_SENDING;
+    p->state = STATE_IOREQ_READY;
+
+    // Try to use ins/outs' framework
+    if (pvalid) {
+        // Handle "movs"
+        p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ?
+                               inst_decoder_regs->esi
+                               : inst_decoder_regs->edi); 
+        p->u.pdata = (void *) gva_to_gpa(p->u.data);
+        p->count = inst_decoder_regs->ecx;
+        inst_decoder_regs->ecx = 0;
+        p->df = (inst_decoder_regs->eflags & EF_DF) ? 1 : 0;
+    }
+
+    evtchn_send(IOPACKET_PORT);
+    do_block(); 
+
+}
+
+void handle_mmio(unsigned long va, unsigned long gpte, unsigned long gpa)
+{
+    unsigned long eip;
+    unsigned long inst_len;
+    struct mi_per_cpu_info *mpci_p;
+    struct xen_regs *inst_decoder_regs;
+    struct instruction mmio_inst;
+    unsigned char inst[MAX_INST_LEN];
+    int ret;
+     
+    mpci_p = &current->thread.arch_vmx.vmx_platform.mpci;
+    inst_decoder_regs = mpci_p->inst_decoder_regs;
+
+    __vmread(GUEST_EIP, &eip);
+    __vmread(INSTRUCTION_LEN, &inst_len);
+
+    memset(inst, '0', MAX_INST_LEN);
+    ret = inst_copy_from_guest(inst, eip, inst_len);
+    if (ret != inst_len) {
+        printk("handle_mmio - EXIT: get guest instruction fault\n");
+        domain_crash();
+    }
+
+    init_instruction(&mmio_inst);
+    
+    if (vmx_decode(check_prefix(inst, &mmio_inst), &mmio_inst) == DECODE_failure)
+        domain_crash();
+
+    __vmwrite(GUEST_EIP, eip + inst_len);
+    store_xen_regs(inst_decoder_regs);
+
+    // Only handle "mov" and "movs" instructions!
+    if (!strncmp(mmio_inst.i_name, "movzw", 5)) {
+        long value = 0;
+        int index;
+
+        if (read_from_mmio(&mmio_inst)) {
+            // Send the request and waiting for return value.
+            mpci_p->mmio_target = mmio_inst.operand[1] | WZEROEXTEND;
+            mmio_inst.op_size = WORD;       
+            send_mmio_req(gpa, &mmio_inst, value, 1, 0);
+        } else {
+            // Write to MMIO
+            if (mmio_inst.operand[0] & IMMEDIATE) {
+                value = mmio_inst.immediate;
+            } else if (mmio_inst.operand[0] & REGISTER) {
+                index = operand_index(mmio_inst.operand[0]);
+                value = get_reg_value(WORD, index, 0, inst_decoder_regs);
+            } else {
+                domain_crash();
+            }
+            mmio_inst.op_size = WORD;
+            send_mmio_req(gpa, &mmio_inst, value, 0, 0);
+            return; 
+        }
+    }
+
+    if (!strncmp(mmio_inst.i_name, "movs", 4)) {
+        int tmp_dir;
+
+        tmp_dir = ((va == inst_decoder_regs->edi) ? IOREQ_WRITE : IOREQ_READ);
+        send_mmio_req(gpa, &mmio_inst, 0, tmp_dir, 1);
+        return;
+    }
+
+    if (!strncmp(mmio_inst.i_name, "mov", 3)) {
+        long value = 0;
+        int size, index;
+
+        if (read_from_mmio(&mmio_inst)) {
+            // Send the request and waiting for return value.
+            mpci_p->mmio_target = mmio_inst.operand[1];
+            send_mmio_req(gpa, &mmio_inst, value, 1, 0);
+        } else {
+            // Write to MMIO
+            if (mmio_inst.operand[0] & IMMEDIATE) {
+                value = mmio_inst.immediate;
+            } else if (mmio_inst.operand[0] & REGISTER) {
+                size = operand_size(mmio_inst.operand[0]);
+                index = operand_index(mmio_inst.operand[0]);
+                value = get_reg_value(size, index, 0, inst_decoder_regs);
+            } else {
+                domain_crash();
+            }
+            send_mmio_req(gpa, &mmio_inst, value, 0, 0);
+            return;
+        }
+        domain_crash();
+    }
+    domain_crash();
+}
+
index b22215688ec88489318c16532b21b8c580c0225c..37ad49b7fa10541b5d0a28c39694f020a81630a7 100644 (file)
@@ -305,10 +305,15 @@ static inline void l1pte_propagate_from_guest(
     case SHM_full_32:
     {
         unsigned long host_pfn, host_gpte;
+        spte = 0;
+
+        if (mmio_space(gpte & 0xFFFFF000)) {
+            *spte_p = spte;
+            return;
+        }
         
         host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
         host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
-        spte = 0;
 
         if ( (host_gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) == 
              (_PAGE_PRESENT|_PAGE_ACCESSED) )
@@ -697,7 +702,7 @@ static inline void __shadow_mk_pagetable( struct mm_struct *mm )
         SH_VVLOG("__shadow_mk_pagetable(guest_gpfn=%08lx, gpfn=%08lx\n", 
                  guest_gpfn, gpfn);
 
-        spfn = __shadow_status(mm, gpfn) & PSH_pfn_mask;
+        spfn = __shadow_status(mm, guest_gpfn) & PSH_pfn_mask;
         if ( unlikely(spfn == 0) ) {
             spfn = shadow_l2_table(mm, gpfn);
             mm->shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
index f2b8a030c1301b939a414eb0081185d228d69459..ed4b234a0e32e92b6e785f782c3fb53e0b1a49e4 100644 (file)
 #ifndef __ASM_X86_VMX_PLATFORM_H__
 #define __ASM_X86_VMX_PLATFORM_H__
 
-#include <asm/e820.h>          /* from Linux */
+#include <asm/e820.h>       /* from Linux */
+
+#define MAX_OPERAND_NUM 3
+#define I_NAME_LEN  16
+
+#define mk_operand(size, index, seg, flag) \
+    (((size) << 24) | ((index) << 16) | ((seg) << 8) | (flag))
+
+#define operand_size(operand)   \
+      ((operand >> 24) & 0xFF)
+
+#define operand_index(operand)  \
+      ((operand >> 16) & 0xFF)
+      //For instruction.operand[].size
+#define BYTE    1
+#define WORD    2
+#define LONG    4
+#define QUAD    8
+
+      //For instruction.operand[].flag
+#define REGISTER    0x1
+#define MEMORY      0x2
+#define IMMEDIATE   0x4
+#define WZEROEXTEND 0x8
+
+      //For instruction.flags
+#define REPZ    0x1
+#define REPNZ   0x2
+
+struct instruction {
+    __s8    i_name[I_NAME_LEN];  //Instruction's name
+    __s16   op_size;    //The operand's bit size, e.g. 16-bit or 32-bit.
+
+    __u64   offset;     //The effective address
+          //offset = Base + (Index * Scale) + Displacement
+
+    __u64   immediate;
+
+    __u16   seg_sel;    //Segmentation selector
+
+    __u32   operand[MAX_OPERAND_NUM];   //The order of operand is from AT&T Assembly
+    __s16   op_num; //The operand numbers
+
+    __u32   flags; //
+};
+
+#define VGA_SPACE_START   0xA0000
+#define VGA_SPACE_END     0xC0000
+#define MAX_INST_LEN      32
+
+struct mi_per_cpu_info
+{
+    unsigned long          mmio_target;
+    struct xen_regs        *inst_decoder_regs;
+};
+
+struct virutal_platform_def {
+    unsigned long          *real_mode_data; /* E820, etc. */
+    unsigned long          shared_page_va;
+    struct mi_per_cpu_info mpci;            /* MMIO */
+};
+
+extern int mmio_space(unsigned long);
+extern void handle_mmio(unsigned long, unsigned long, unsigned long);
+extern int vmx_setup_platform(struct exec_domain *, execution_context_t *);
+
+extern inline int mmio_space(unsigned long gpa)
+{
+    if (gpa >= VGA_SPACE_START && gpa < VGA_SPACE_END) {
+        return 1;
+    }
+    return 0;
+}
 
 #endif
index 8ec77d8ed5abcd129a564ba792d81d729ff17535..40d315d609dbd8d7603b6d3c97b83a6a82043749 100644 (file)
@@ -39,15 +39,7 @@ union vmcs_arbytes {
     unsigned int bytes;
 };
 
-struct virutal_platform_def {
-    unsigned long   *real_mode_data; /* E820, etc. */
-    unsigned long   shared_page_va;
-};
-
-int vmx_setup_platform(struct exec_domain *, execution_context_t *);
-
 #define VMX_CPU_STATE_PG_ENABLED        0       
-
 #define VMCS_SIZE                       0x1000
 
 struct vmcs_struct {
@@ -62,10 +54,6 @@ struct arch_vmx_struct {
     unsigned long           cpu_cr3;
     unsigned long           cpu_state;
     struct virutal_platform_def     vmx_platform; 
-#if 0
-    /* open */
-    unsigned long *page_list; /* page list for MMIO */
-#endif
 };
 
 #define vmx_schedule_tail(next)         \